dgb: M3 §7b DigiShield Scrypt-only retarget (rebased on master@064a717d) - #153
Merged
Conversation
Isolates the consensus quirk flagged at header_chain.hpp DIGISHIELD INSERTION POINT: the Scrypt difficulty window must walk Scrypt-algo ancestors ONLY and skip continuity (non-Scrypt) headers; folding a continuity header into the window corrupts the Scrypt retarget and breaks the THIRD INVARIANT work- neutrality. Adds header_credits_work() as the single SSOT predicate the validate() work-accounting and the retarget walk both consult, so they cannot drift. Header-only (deps: dgb_block_algo.hpp + std), so it links into the standalone GTest guard with no dgb OBJECT lib. - coin/dgb_digishield.hpp: scrypt_window_ancestors(), header_credits_work() - test/digishield_walk_test.cpp: 6 guards (zero-bits Scrypt, interleave skip, leading-continuity run, exhausted chain, zero window, work predicate) - wired into BOTH ctest foreach AND both build.yml --target allowlists (#143) Per-algo DigiShield target math layers on top in the following slice.
Replace the header_chain.hpp namespace stub with the validate() body that drives the Scrypt-only chain: per-header disposition (Scrypt validate / accept-by-continuity / reject), work-neutral accounting, and the Scrypt-only DigiShield retarget-window assembly (averaged target + actual timespan). Work-neutrality SSOT: cumulative work advances iff header_credits_work(), the same predicate scrypt_window_ancestors() consults for the retarget window, so the work-accounting and retarget paths cannot drift. Continuity headers extend the chain but credit zero work and are excluded from the retarget window. THIRD INVARIANT under test: a continuity header inside the nominal window is proven skipped from both avg_target and actual_timespan (a naive all-headers window would corrupt both). The damped DigiShield/MultiShield arith_uint256 multiply layers on RetargetWindow in the following slice. Guard header_chain_test wired into the ctest foreach AND both build.yml --target allowlists (the #143 NOT_BUILT lesson). 6/6 PASS, build EXIT=0.
digishield_next_target() + DigiShieldParams in coin/header_chain.hpp: consumes the Scrypt-only RetargetWindow (avg_target + actual_timespan over Scrypt ancestors only) and produces the next expanded target via DigiByte DigiShield v3: amplitude filter damped = nominal + (actual-nominal)/8, clamp to [3/4, 3/2] nominal rails, bnNew = avg*damped/nominal, capped to pow_limit. __int128 intermediate (proxy-overflow safe); arith_uint256 swaps in later with the same field shape. Returns 0 on empty window / degenerate nominal so the caller keeps the prior target. header_chain_test: +6 DigiShield cases -- nominal (target unchanged), both clamp rails (ceiling 3/2, floor 3/4 via negative timespan), pow_limit floor, empty-window/zero-nominal safety, and end-to-end over the live continuity- skipped window. 12/12 pass, build EXIT=0. Header-only; reuses the already- wired header_chain_test guard (no new ctest/build.yml target).
validate_and_append now enforces the DigiShield-computed next target on the VALIDATE_SCRYPT path: the declared Scrypt target must EQUAL the next-target computed over the Scrypt-only retarget window ending at the current tip (assembled before the header is appended), the nBits-style consensus rule. A configured HeaderChain(DigiShieldParams, window) arms the gate; a default- constructed chain leaves target_timespan 0 so digishield_next_target() returns the 0 sentinel and the gate is a no-op (existing retarget/work-accounting tests run unconstrained, unchanged). A rejected header never mutates the chain (size + cumulative work preserved). +1 ingest-gate test vector (window 1, deterministic 7/8 next-target): wrong target REJECTED with chain unchanged, exact target VALIDATED_SCRYPT crediting work, continuity header bypasses the gate. Added INTO header_chain_test (no new gtest target -> #143 NOT_BUILT trap avoided). 13/13 PASS, build EXIT=0.
Swap the uint64/__int128 retarget intermediate for a header-only 256-bit unsigned (coin/dgb_arith256.hpp) reproducing arith_uint256 multiply-then- divide with 256-bit overflow truncation -- the consensus arithmetic of DigiByte Core CalculateNextWorkRequired. For uint64-range avg_target the path is bit-identical to the prior intermediate, so the existing 13 vectors are unchanged; +5 boundary vectors prove the divergence above 2^64 and the 256-bit truncation near pow_limit that an __int128 proxy could not reproduce. Header-only, single-coin (src/impl/dgb only), tests added into header_chain_test (no new gtest target).
VALIDATE_SCRYPT path now rejects a declared Scrypt target EASIER than pow_limit (target > pow_limit), mirroring DigiByte Core CheckProofOfWork. This fires on the bootstrap/empty-window path (expected == 0) where the nBits-style retarget-equality gate is a no-op, closing the hole where a sub-minimum-difficulty header could seed/extend the chain during a stall. pow_limit == 0 keeps the gate unconfigured (legacy default-ctor chains unconstrained). +1 vector folded into header_chain_test (no new gtest target; #143 NOT_BUILT trap avoided). 19/19 PASS, build EXIT=0.
CheckProofOfWork second half: the VALIDATE_SCRYPT path now rejects a header whose scrypt(header) digest exceeds its declared target (hash > target). Half 1 (target <= pow_limit) already landed; this closes the missing PoW-satisfaction guard that was a placeholder. HeaderSample gains a uint64 pow_hash proxy (mirrors ltc coin/header_chain hash field). Context-free check, run after the pow_limit ceiling and before the contextual nBits-equality gate, mirroring DigiByte Core if (UintToArith256(hash) > bnTarget) return false. pow_hash == 0 is the standalone default (trivially satisfies any target) so every existing vector is unchanged; the embedded-daemon port fills the real digest into the same field shape. +1 vector folded INTO header_chain_test (no new gtest target, #143 trap avoided): rejects pow_hash > target, accepts == and < boundary, and confirms a continuity header short-circuits before the PoW check. header_chain_test 20/20 PASS, build EXIT=0.
…u256) Swap HeaderSample::target/pow_hash, RetargetWindow::avg_target, DigiShieldParams::pow_limit and the digishield_next_target() return from uint64 proxies to the full-width u256 (coin/dgb_arith256.hpp). An implicit uint64 widening ctor keeps every uint64-range vector byte-identical, so the ingest PoW-satisfaction + minimum-difficulty ceiling checks and the DigiShield averaging now run at true arith_uint256 width through validate_and_append. Adds u256 operator+= for the window target-sum average. +1 ingest-path boundary vector folded into header_chain_test (no new gtest target): a >2^64 target/digest decides acceptance the same way arith_uint256 would and diverges from a low64-only proxy in both directions. 21/21 PASS. Confined to src/impl/dgb/; no shared base / bitcoin_family / CMake / build.yml touch.
frstrtr
added a commit
that referenced
this pull request
Jun 19, 2026
dgb: M3 §7b scrypt-digest conversion + retarget no-op + MTP guard (tail, rebased on master post-#153)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
§7b — DigiShield Scrypt-only retarget (DGB single-coin)
Rebased onto master@064a717d (post #150/#151/#152 merges). Five GPG-signed commits, zero conflict drift from the three landed branches.
Commits (bottom -> top)
98bf557fDigiShield Scrypt-only ancestor walk + work-credit predicate (dgb_digishield.hppSSOT)25822a5cHeaderChain Scrypt-onlyvalidate()body + retarget-window over Scrypt samples only587d9f19per-algo DigiShield damped retarget multiply (v3 damped = nominal + (actual-nominal)/8, clamp [3/4, 3/2])f524643awire DigiShield next-target into HeaderChain ingest gate (nBits-style exact-match)ca21fdd1damped multiply at true 256-bit width (dgb_arith256.hpp, mul-then-div = DGB Core order)Scope guardrails
src/impl/dgb/.header_chain_test(no separate target for the vectors) — preserves the ci: build test_dgb_subsidy in both Linux test jobs (fix master-red NOT_BUILT) #143 dodge.digishield_walk_test,header_chain_test) are each wired into BOTH the ctest foreach AND BOTH build.yml--targetallowlists (the ci: build test_dgb_subsidy in both Linux test jobs (fix master-red NOT_BUILT) #143-SAFE pattern; a registered-but-unbuilt gtest would red master as a NOT_BUILT sentinel). This is the only build.yml change — required, not avoidable.Verification
digishield_walk_test6/6 PASSheader_chain_test18/18 PASS (incl 5 DigiShield256 >2^64 / 256-bit-truncation boundary vectors + continuity-skip acceptance)